home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 4 / Info_Mac IV CD-ROM (Pacific HiTech Inc.)(August 1994).iso / Text Processing / Pairs 1.0 / BBEdit Extension / Pairs.c < prev    next >
C/C++ Source or Header  |  1994-03-13  |  38KB  |  1,119 lines

  1. // Pairs.c
  2. //
  3. // BBEdit external tool to search for mismatched brace, quote, and comment delimiter pairs
  4.  
  5. #define SystemSevenOrLater 1
  6. #if !USESROUTINEDESCRIPTORS
  7. #include <A4Stuff.h>
  8. #endif // !USESROUTINEDESCRIPTORS
  9. #include <Dialogs.h>
  10. #include <ExternalInterface.h>
  11. #include <LowMem.h>
  12. #include <Memory.h>
  13. #include <Resources.h>
  14. #if !USESROUTINEDESCRIPTORS
  15. #include <SetupA4.h>
  16. #endif // !USESROUTINEDESCRIPTORS
  17. #include <StdDef.h>
  18. #include <ToolUtils.h>
  19. #include <Types.h>
  20.  
  21. // function prototypes
  22. #if !USESROUTINEDESCRIPTORS
  23. QDGlobals *GetQDPointer(void);
  24. #endif // !USESROUTINEDESCRIPTORS
  25. pascal Boolean DoCustomModalAlertFilter(DialogPtr pdlgAlert,EventRecord *pevntAlert,short *psHit,short sAlertType);
  26. pascal Boolean CustomModalDialogPreprocessFilter(DialogPtr pdlgGeneric,EventRecord *pevntGeneric,short *psHit);
  27. pascal Boolean CustomModalNoteAlertFilter(DialogPtr pdlgAlert,EventRecord *pevntAlert,short *psHit);
  28. pascal Boolean CustomModalCautionAlertFilter(DialogPtr pdlgAlert,EventRecord *pevntAlert,short *psHit);
  29. pascal Boolean CustomModalStopAlertFilter(DialogPtr pdlgAlert,EventRecord *pevntAlert,short *psHit);
  30. void ReportError(ExternalCallbackBlock *pcallBBEdit,Str255 strError1,Str255 strError2);
  31. void ReportMismatch(ExternalCallbackBlock *pcallBBEdit,Str255 strMismatch);
  32. void ReportNoMismatch(ExternalCallbackBlock *pcallBBEdit,Str255 strNoMismatch);
  33. pascal Boolean DoCustomModalDialogFilter(DialogPtr pdlgGeneric,EventRecord *pevntGeneric,short *psHit);
  34. pascal Boolean CustomModalDialogFilter(DialogPtr pdlgGeneric,EventRecord *pevntGeneric,short *psHit);
  35. Boolean PairsDialog(ExternalCallbackBlock *pcallBBEdit,int *piMode);
  36. Boolean CheckBraces(ExternalCallbackBlock *pcallBBEdit,int iMode,Handle hText,long lStartPos,long lEndPos);
  37. Boolean CheckQuotes(ExternalCallbackBlock *pcallBBEdit,int iMode,Handle hText,long lStartPos,long lEndPos);
  38. Boolean CheckComments(ExternalCallbackBlock *pcallBBEdit,Handle hText,long lStartPos,long lEndPos);
  39. pascal void main(ExternalCallbackBlock *pcallBBEdit,WindowPtr pwndFront);
  40.  
  41. // alert type constants
  42. #define NOTE_ALERT            0
  43. #define CAUTION_ALERT        2
  44. #define STOP_ALERT            1
  45.  
  46. // edit mode function selection constants
  47. #define MODE_CURLY_BRACE    0
  48. #define MODE_SQUARE_BRACE    1
  49. #define MODE_PARENTHESIS    2
  50. #define MODE_DBL_QUOTE        3
  51. #define MODE_SNGL_QUOTE        4
  52. #define MODE_COMMENT        5
  53.  
  54. // dialog constants
  55. #define ALERT_ID            128
  56. #define DITL_ID                129
  57. #define OK_BUTTON            1
  58. #define CANCEL_BUTTON        2
  59. #define CURLY_BRACE_RADIO    3
  60. #define SQUARE_BRACE_RADIO    4
  61. #define PARENTHESIS_RADIO    5
  62. #define DBL_QUOTE_RADIO        6
  63. #define SNGL_QUOTE_RADIO    7
  64. #define COMMENT_RADIO        8
  65. #define DEFAULT_BUTTON        9
  66. #define RADIO_LABEL            10
  67.  
  68. // brace-related constants
  69. #define NO_ERROR            0
  70. #define BAD_COMMENT            1
  71. #define BAD_LEFT            2
  72. #define BAD_RIGHT            3
  73. #define BAD_NESTED            4
  74. #define BAD_QUOTE            5
  75. #define SLASH                '/'
  76. #define BACK_SLASH            '\\'
  77. #define STAR                '*'
  78. #define SNGL_QUOTE            '\''
  79. #define DBL_QUOTE            '"'
  80. #define EOL                    '\r'
  81.  
  82. // global variables
  83. ModalFilterUPP gumfBBEdit;
  84.  
  85. #if !USESROUTINEDESCRIPTORS
  86. QDGlobals *GetQDPointer(void)
  87. // return a pointer to the application's qd global variable
  88.  
  89. {
  90. return ((QDGlobals *)(*(char **)LMGetCurrentA5() - offsetof(QDGlobals,thePort)));    // A5 points to qd.thePort
  91. }  // GetQDPointer()
  92. #endif // !USESROUTINEDESCRIPTORS
  93.  
  94. pascal Boolean DoCustomModalAlertFilter(DialogPtr pdlgAlert,EventRecord *pevntAlert,short *psHit,short sAlertType)
  95. // alert input filter which installs standard default and cancel keys, allowing the system modal dialog filter to handle all keydown and update events
  96.  
  97. {
  98. Boolean boolNeedIcon,boolRetVal;
  99. short sIconType;
  100. #if !USESROUTINEDESCRIPTORS
  101. long lSaveA4;
  102. #endif // !USESROUTINEDESCRIPTORS
  103. Handle hTemp;
  104. Rect rctTemp;
  105. GrafPtr pgrfSave;
  106.  
  107. #if !USESROUTINEDESCRIPTORS
  108. lSaveA4 = SetUpA4();                                                                // ensure correct access to the global variables
  109. #endif // !USESROUTINEDESCRIPTORS
  110. boolRetVal = false;                                                                    // initialize
  111. if (pevntAlert->what == updateEvt)
  112.     {
  113.     if ((WindowPtr) pevntAlert->message == pdlgAlert)
  114.         {
  115.         // most alert updating is automatically handled, but not all. first deal with redrawing the icons in note, caution, and stop alerts
  116.         boolNeedIcon = true;                                                        // initialize
  117.         switch (sAlertType)
  118.             {
  119.             case NOTE_ALERT :
  120.                 {
  121.                 sIconType = noteIcon;                                                // signal what cicn/ICON resource ID is needed
  122.                 break;
  123.                 }  // case NOTE_ALERT
  124.             case CAUTION_ALERT :
  125.                 {
  126.                 sIconType = cautionIcon;                                            // signal what cicn/ICON resource ID is needed
  127.                 break;
  128.                 }  // case CAUTION_ALERT
  129.             case STOP_ALERT :
  130.                 {
  131.                 sIconType = stopIcon;                                                // signal what cicn/ICON resource ID is needed
  132.                 break;
  133.                 }  // case STOP_ALERT
  134.             default :
  135.                 {
  136.                 // plain alert, or who knows what : do nothing
  137.                 boolNeedIcon = false;                                                // signal no icon required
  138.                 break;
  139.                 }  // default;
  140.             }  // switch sAlertType
  141.         if (boolNeedIcon)
  142.             {
  143.             GetPort(&pgrfSave);                                                        // save the current port
  144.             SetPort(pdlgAlert);                                                        // make sure the alert port is the current one
  145.  
  146.             // set standard icon rect
  147.             rctTemp.top = 10;
  148.             rctTemp.left = 20;
  149.             rctTemp.bottom = 42;
  150.             rctTemp.right = 52;
  151.  
  152.             // first try to get a cicn
  153.             hTemp = (Handle) GetCIcon(sIconType);
  154.             if (hTemp != nil)
  155.                 {
  156.                 PlotCIcon(&rctTemp,(CIconHandle) hTemp);                            // plot the cicn
  157.                 DisposeCIcon((CIconHandle) hTemp);                                    // get rid of the cicn handle
  158.                 }  // if hTemp
  159.             else
  160.                 {
  161.                 // try for a B+W icon
  162.                 hTemp = (Handle) GetIcon(sIconType);
  163.                 if (hTemp != nil)
  164.                     {
  165.                     PlotIcon(&rctTemp,hTemp);                                        // plot the ICON
  166.                     ReleaseResource(hTemp);                                            // get rid of the ICON handle
  167.                     }  // if hTemp
  168.                 }  // else if hTemp
  169.             SetPort(pgrfSave);                                                        // restore the old port
  170.             }  // if boolNeedIcon
  171.         
  172.         // the rest (button outlining) is done by calling the standard BBEdit dialog handler
  173.         boolRetVal = CallModalFilterProc(gumfBBEdit,pdlgAlert,pevntAlert,psHit);
  174.         }  // else if pevntAlert->message
  175.     else
  176.         {
  177.         // pass on non-alert update processing as required
  178.         boolRetVal = CallModalFilterProc(gumfBBEdit,pdlgAlert,pevntAlert,psHit);
  179.         }  // if pevntAlert->message
  180.     }  // if pevntAlert->what
  181. else
  182.     {
  183.     boolRetVal = CustomModalDialogPreprocessFilter(pdlgAlert,pevntAlert,psHit);        // call the preprocess filter that handles window command-drags
  184.     if (!boolRetVal)
  185.         {
  186.         // the event hasn't been handled yet
  187.         boolRetVal = CallModalFilterProc(gumfBBEdit,pdlgAlert,pevntAlert,psHit);
  188.         }  // if !boolRetVal;
  189.     }  // else if pevntAlert->what
  190. #if !USESROUTINEDESCRIPTORS
  191. (void) RestoreA4(lSaveA4);                                                            // restore the previous A4 world
  192. #endif // !USESROUTINEDESCRIPTORS
  193. return boolRetVal;                                                                    // signal if processing is complete
  194. }  // DoCustomModalAlertFilter()
  195.  
  196. pascal Boolean CustomModalDialogPreprocessFilter(DialogPtr pdlgGeneric,EventRecord *pevntGeneric,short *psHit)
  197. // modal dialog filter function for handling drag events
  198. // note that this function always returns false, allowing it to be used with modal dialogs and alerts
  199. // if it returned true after handling a drag, normal modal dialogs would work OK, but alerts would be dismissed after the drag
  200. // apparently the system dismisses the alert whenever the alert's modal filter function returns true
  201.  
  202. {
  203. short sPart;
  204. WindowPtr pwndEvent;
  205. #if !USESROUTINEDESCRIPTORS
  206. QDGlobals *pqdGlobals;
  207. #endif // !USESROUTINEDESCRIPTORS
  208.  
  209. if (pevntGeneric->what == mouseDown)
  210.     {
  211.     // handle a click
  212.     sPart = FindWindow(pevntGeneric->where,&pwndEvent);
  213.     if ((sPart == inDrag) && ((pevntGeneric->modifiers & cmdKey) || (pwndEvent == pdlgGeneric)))
  214.         {
  215.         // allow command-dragging of own application's background windows, or normal dragging of the current window
  216. #if USESROUTINEDESCRIPTORS
  217.         DragWindow(pwndEvent,pevntGeneric->where,&qd.screenBits.bounds);
  218. #else
  219.         pqdGlobals = GetQDPointer();            // get a pointer to the qd globals
  220.         DragWindow(pwndEvent,pevntGeneric->where,&pqdGlobals->screenBits.bounds);
  221. #endif // USESROUTINEDESCRIPTORS
  222.         pevntGeneric->what = nullEvent;            // change to a null-event to prevent beeps, etc.
  223.         }  // if sPart
  224.     }  // if pevntGeneric->what
  225. return false;                                    // signal that the event wasn't handled
  226. }  // CustomModalDialogPreprocessFilter()
  227.  
  228. pascal Boolean CustomModalStopAlertFilter(DialogPtr pdlgAlert,EventRecord *pevntAlert,short *psHit)
  229. // outer shell for the actual stop alert input filter
  230.  
  231. {
  232. Boolean boolRetVal;
  233.  
  234. boolRetVal = DoCustomModalAlertFilter(pdlgAlert,pevntAlert,psHit,STOP_ALERT);    // call the actual modal filter as a separate function, to avoid optimizing compilers from messing up the SetCurrentA4 operation
  235. return boolRetVal;                                                                // signal if processing is complete
  236. }  // CustomModalStopAlertFilter()
  237.  
  238. pascal Boolean CustomModalCautionAlertFilter(DialogPtr pdlgAlert,EventRecord *pevntAlert,short *psHit)
  239. // outer shell for the actual caution alert input filter
  240.  
  241. {
  242. Boolean boolRetVal;
  243.  
  244. boolRetVal = DoCustomModalAlertFilter(pdlgAlert,pevntAlert,psHit,CAUTION_ALERT);    // call the actual modal filter as a separate function, to avoid optimizing compilers from messing up the SetCurrentA4 operation
  245. return boolRetVal;                                                                    // signal if processing is complete
  246. }  // CustomModalStopAlertFilter()
  247.  
  248. pascal Boolean CustomModalNoteAlertFilter(DialogPtr pdlgAlert,EventRecord *pevntAlert,short *psHit)
  249. // outer shell for the actual note alert input filter
  250.  
  251. {
  252. Boolean boolRetVal;
  253. boolRetVal = DoCustomModalAlertFilter(pdlgAlert,pevntAlert,psHit,NOTE_ALERT);    // call the actual modal filter as a separate function, to avoid optimizing compilers from messing up the SetCurrentA4 operation
  254. return boolRetVal;                                                                // signal if processing is complete
  255. }  // CustomModalNoteAlertFilter()
  256.  
  257. void ReportError(ExternalCallbackBlock *pcallBBEdit,Str255 strError1,Str255 strError2)
  258. // put up an error dialog
  259.  
  260. {
  261. ModalFilterUPP umfAlert;
  262.  
  263. #if !USESROUTINEDESCRIPTORS
  264. RememberA4();                                                    // remember the current A4 data segment pointer
  265. #endif // !USESROUTINEDESCRIPTORS
  266. umfAlert = NewModalFilterProc(CustomModalStopAlertFilter);        // get a routine descriptor (or UniversalProcPtr for 68k) for the stop alert dialog filter function
  267. ParamText("\pPairs",strError1,strError2,"\p");
  268. (void) StopAlert(ALERT_ID,umfAlert);
  269. DisposeRoutineDescriptor((UniversalProcPtr) umfAlert);            // dispose of the routine descriptor
  270. }  // ReportError()
  271.  
  272. void ReportMismatch(ExternalCallbackBlock *pcallBBEdit,Str255 strMismatch)
  273. // put up a pair check status dialog
  274.  
  275. {
  276. ModalFilterUPP umfAlert;
  277.  
  278. #if !USESROUTINEDESCRIPTORS
  279. RememberA4();                                                    // remember the current A4 data segment pointer
  280. #endif // !USESROUTINEDESCRIPTORS
  281. umfAlert = NewModalFilterProc(CustomModalCautionAlertFilter);    // get a routine descriptor (or UniversalProcPtr for 68k) for the caution alert dialog filter function
  282. ParamText("\pPairs",strMismatch,"\p","\p");
  283. (void) CautionAlert(ALERT_ID,umfAlert);
  284. DisposeRoutineDescriptor((UniversalProcPtr) umfAlert);            // dispose of the routine descriptor
  285. }  // ReportMismatch()
  286.  
  287. void ReportNoMismatch(ExternalCallbackBlock *pcallBBEdit,Str255 strNoMismatch)
  288. // put up a pair check status dialog
  289.  
  290. {
  291. ModalFilterUPP umfAlert;
  292.  
  293. #if !USESROUTINEDESCRIPTORS
  294. RememberA4();                                                    // remember the current A4 data segment pointer
  295. #endif // !USESROUTINEDESCRIPTORS
  296. umfAlert = NewModalFilterProc(CustomModalNoteAlertFilter);        // get a routine descriptor (or UniversalProcPtr for 68k) for the note alert dialog filter function
  297. ParamText("\pPairs",strNoMismatch,"\p","\p");
  298. (void) NoteAlert(ALERT_ID,umfAlert);
  299. DisposeRoutineDescriptor((UniversalProcPtr) umfAlert);            // dispose of the routine descriptor
  300. }  // ReportNoMismatch()
  301.  
  302. static pascal Boolean DoCustomModalDialogFilter(DialogPtr pdlgGeneric,EventRecord *pevntGeneric,short *psHit)
  303. // dialog input filter
  304.  
  305. {
  306. Boolean boolRetVal;
  307. #if !USESROUTINEDESCRIPTORS
  308. long lSaveA4;
  309.  
  310. lSaveA4 = SetUpA4();                                                                    // ensure correct access to the global variables
  311. #endif // !USESROUTINEDESCRIPTORS
  312. boolRetVal = false;                                                                        // initialize
  313. if (pevntGeneric->what == updateEvt)
  314.     {
  315.     boolRetVal = CallModalFilterProc(gumfBBEdit,pdlgGeneric,pevntGeneric,psHit);
  316.     }  // if pevntGeneric->what
  317. else
  318.     {
  319.     boolRetVal = CustomModalDialogPreprocessFilter(pdlgGeneric,pevntGeneric,psHit);        // call the preprocess filter that handles window command-drags
  320.     if (!boolRetVal)
  321.         {
  322.         // the event hasn't been handled yet
  323.         boolRetVal = CallModalFilterProc(gumfBBEdit,pdlgGeneric,pevntGeneric,psHit);
  324.         }  // if !boolRetVal
  325.     }  // else if pevntGeneric->what
  326. #if !USESROUTINEDESCRIPTORS
  327. (void) RestoreA4(lSaveA4);                                                                // restore the previous A4 world
  328. #endif // !USESROUTINEDESCRIPTORS
  329. return boolRetVal;                                                                        // signal if processing is complete
  330. }  // DoCustomModalDialogFilter()
  331.  
  332. pascal Boolean CustomModalDialogFilter(DialogPtr pdlgGeneric,EventRecord *pevntGeneric,short *psHit)
  333. // outer shell for the actual dialog input filter
  334.  
  335. {
  336. Boolean boolRetVal;
  337.  
  338. boolRetVal = DoCustomModalDialogFilter(pdlgGeneric,pevntGeneric,psHit);        // call the actual modal filter as a separate function, to avoid optimizing compilers from messing up the SetCurrentA4 operation
  339. return boolRetVal;                                                            // signal if processing is complete
  340. }  // CustomModalDialogFilter()
  341.  
  342. Boolean PairsDialog(ExternalCallbackBlock *pcallBBEdit,int *piMode)
  343. // Pairs edit dialog box routine
  344.  
  345. {
  346. Boolean boolRetVal;
  347. short sDummy,sIndex,sHit,sTemp;
  348. DialogPtr pdlogPairs;
  349. Rect rectTemp;
  350. Handle hdlogItem;
  351. ControlHandle hctrlItem,hctrlTemp;
  352. ModalFilterUPP umfDialog;
  353.  
  354. #if !USESROUTINEDESCRIPTORS
  355. RememberA4();                                                                                                            // remember the current A4 data segment pointer
  356. #endif // !USESROUTINEDESCRIPTORS
  357. pdlogPairs = GetNewDialog(DITL_ID,NULL,(WindowPtr) -1);                                                                    // bring in the dialog resource
  358. if (pdlogPairs != NULL)
  359.     {
  360.     SetPort(pdlogPairs);                                                                                                // ensure the correct port is current
  361.     umfDialog = NewModalFilterProc(CustomModalDialogFilter);                                                            // get a routine descriptor (or UniversalProcPtr for 68k) for the custom dialog filter function
  362.     
  363.     // set up radio buttons to a default value
  364.     for (sIndex = CURLY_BRACE_RADIO; sIndex <= COMMENT_RADIO; sIndex++)
  365.         {
  366.         // clear all radios
  367.         GetDialogItem(pdlogPairs,sIndex,&sDummy,&hdlogItem,&rectTemp);                                                    // get the item handle
  368.         hctrlTemp = (ControlHandle) hdlogItem;                                                                            // get the control handle
  369.         SetControlValue(hctrlTemp,0);                                                                                    // turn the radio selection off
  370.         }  // for sIndex
  371.     GetDialogItem(pdlogPairs,CURLY_BRACE_RADIO,&sDummy,&hdlogItem,&rectTemp);                                            // get the item handle
  372.     hctrlItem = (ControlHandle) hdlogItem;                                                                                // get the control handle
  373.     SetControlValue(hctrlItem,1);                                                                                        // select the radio
  374.     
  375.     ShowWindow(pdlogPairs);                                                                                                // open a dialog box
  376.     SelectWindow(pdlogPairs);                                                                                             // make it visible
  377.     
  378.     do
  379.         {
  380.         ModalDialog(umfDialog,&sHit);                                                                                    // wait until an item is hit
  381.         GetDialogItem(pdlogPairs,sHit,&sDummy,&hdlogItem,&rectTemp);                                                     // get item information
  382.         hctrlItem = (ControlHandle) hdlogItem;                                                                            // get the control handle
  383.         
  384.         switch (sHit)
  385.             {
  386.             case CURLY_BRACE_RADIO :
  387.             case SQUARE_BRACE_RADIO :
  388.             case PARENTHESIS_RADIO :
  389.             case DBL_QUOTE_RADIO :
  390.             case SNGL_QUOTE_RADIO :
  391.             case COMMENT_RADIO :
  392.                 {
  393.                 for (sIndex = CURLY_BRACE_RADIO; sIndex <= COMMENT_RADIO; sIndex++)
  394.                     {
  395.                     // clear all radios
  396.                     GetDialogItem(pdlogPairs,sIndex,&sDummy,&hdlogItem,&rectTemp);                                        // get the item handle
  397.                     hctrlTemp = (ControlHandle) hdlogItem;                                                                // get the control handle
  398.                     SetControlValue(hctrlTemp,0);                                                                        // turn the radio selection off
  399.                     }  // for sIndex
  400.                 SetControlValue(hctrlItem,1);                                                                            // turn the one radio selection on
  401.                 break;
  402.                 }  // case CURLY_BRACE_RADIO … COMMENT_RADIO
  403.             }  // switch sHit
  404.         }  // do
  405.     while ((sHit != OK_BUTTON) && (sHit != CANCEL_BUTTON));
  406.     
  407.     // Get results after dialog
  408.     if (sHit == CANCEL_BUTTON)
  409.         {
  410.         boolRetVal = true;
  411.         }  // if sHit
  412.     else
  413.         {
  414.         boolRetVal = false;
  415.         }  // else if sHit
  416.     if (!boolRetVal)
  417.         {
  418.         sIndex = CURLY_BRACE_RADIO;                                                                                        // start at the first radio in this group
  419.         do
  420.             {
  421.             GetDialogItem(pdlogPairs,sIndex,&sDummy,&hdlogItem,&rectTemp);                                                // get the item handle
  422.             hctrlItem = (ControlHandle) hdlogItem;                                                                        // get the control handle
  423.             sTemp = GetControlValue(hctrlItem);                                                                            // get the radio value
  424.             sIndex++;
  425.             }  // do
  426.         while ((sTemp != 1) && (sIndex <= COMMENT_RADIO));
  427.         *piMode = sIndex - CURLY_BRACE_RADIO - 1;
  428.         boolRetVal = false;
  429.         }  // if !boolRetVal
  430.     DisposeDialog(pdlogPairs);                                                                                             // flush the dialog out of memory
  431.     DisposeRoutineDescriptor((UniversalProcPtr) umfDialog);                                                                // dispose of the routine descriptor
  432.     }  // if pdlogPairs
  433. else
  434.     {
  435.     ReportError(pcallBBEdit,"\pUnable to continue:","\pCan't create the dialog box.");
  436.     boolRetVal = false;                                                                                                    // signal don't continue
  437.     }  // else if pdlogPairs
  438. return boolRetVal;
  439. }  // PairsDialog()
  440.  
  441. Boolean CheckBraces(ExternalCallbackBlock *pcallBBEdit,int iMode,Handle hText,long lStartPos,long lEndPos)
  442. // find mismatched curly and square brackets and parenthesis
  443.  
  444. {
  445. Boolean boolDone,boolIn1Quote,boolIn2Quote,boolInCComment,boolInCPlusComment,boolSelect;
  446. char chCurrent,chLastChar,chLeftMatch,chRightMatch,chSecondToLastChar;
  447. int iError;
  448. long lCurPos,lEOFPos,lMatch,lSavePos;
  449.  
  450. switch (iMode)
  451.     {
  452.     case MODE_CURLY_BRACE :
  453.         {
  454.         chLeftMatch = '{';
  455.         chRightMatch = '}';
  456.         break;
  457.         }  // case MODE_CURLY_BRACE
  458.     case MODE_SQUARE_BRACE :
  459.         {
  460.         chLeftMatch = '[';
  461.         chRightMatch = ']';
  462.         break;
  463.         }  // case MODE_SQUARE_BRACE
  464.     case MODE_PARENTHESIS :
  465.         {
  466.         chLeftMatch = '(';
  467.         chRightMatch = ')';
  468.         break;
  469.         }  // case MODE_PARENTHESIS
  470.     default :
  471.         {
  472.         // do nothing
  473.         break;
  474.         }  // default
  475.     }  // switch iMode
  476. lEOFPos = GetHandleSize(hText);
  477. boolSelect = (lEndPos > lStartPos);
  478. boolDone = false;
  479. boolIn1Quote = false;
  480. boolIn2Quote = false;
  481. boolInCComment = false;
  482. boolInCPlusComment = false;
  483. chLastChar = '\0';
  484. chSecondToLastChar = '\0';
  485. lCurPos = lStartPos;
  486. lSavePos = lStartPos;
  487. lMatch = 0L;
  488. iError = NO_ERROR;
  489.  
  490. while(!boolDone)
  491.     {
  492.     chCurrent = (char) *((*hText) + lCurPos);                        // read a single character
  493.     if (lCurPos < lEOFPos)
  494.         {
  495.         if (chCurrent == chLeftMatch)
  496.             {
  497.             if (!boolIn1Quote && !boolIn2Quote && !boolInCComment && !boolInCPlusComment)
  498.                 {
  499.                 lMatch++;                                            // increment the pair count
  500.                 if (lMatch == 1)
  501.                     {
  502.                     lSavePos = lCurPos;                                // save the current character number
  503.                     }  // if lMatch
  504.                 }  // if !boolIn1Quote
  505.             }  // if chCurrent
  506.         else
  507.             {
  508.             if (chCurrent == chRightMatch)
  509.                 {
  510.                 if (!boolIn1Quote && !boolIn2Quote && !boolInCComment && !boolInCPlusComment)
  511.                     {
  512.                     lMatch--;                                        // decrement the pair count
  513.                     if (lMatch  < 0)
  514.                         {
  515.                         boolDone = true;                            // signal quit
  516.                         iError = BAD_RIGHT;                            // signal mismatched right pair
  517.                         }  // if lMatch
  518.                     }  // if !boolIn1Quote
  519.                 }  // if chCurrent
  520.             else
  521.                 {
  522.                 switch (chCurrent)
  523.                     {
  524.                     case SNGL_QUOTE :
  525.                         {
  526.                         if (!boolIn2Quote && !boolInCComment && !boolInCPlusComment)
  527.                             {
  528.                             if (!(boolIn1Quote && (chLastChar == BACK_SLASH) && (chSecondToLastChar != BACK_SLASH)))
  529.                                 {
  530.                                 // this is not an escaped quote
  531.                                 boolIn1Quote = !boolIn1Quote;        // toggle the "in single quote" status
  532.                                 }  // if !boolInQuote1
  533.                             }  // if !boolIn2Quote
  534.                             break;
  535.                         }  // case SNGL_QUOTE
  536.                     case DBL_QUOTE :
  537.                         {
  538.                         if (!boolIn1Quote && !boolInCComment && !boolInCPlusComment)
  539.                             {
  540.                             if (!(boolIn2Quote && (chLastChar == BACK_SLASH) && (chSecondToLastChar != BACK_SLASH)))
  541.                                 {
  542.                                 // this is not an escaped quote
  543.                                 boolIn2Quote = !boolIn2Quote;        // toggle the "in double quote" status
  544.                                 }  // if !boolInQuote1
  545.                             }  // if !boolIn1Quote
  546.                         break;
  547.                         }  // case DBL_QUOTE
  548.                     case SLASH :
  549.                         {
  550.                         if (!boolIn1Quote && !boolIn2Quote && !boolInCPlusComment)
  551.                             {
  552.                             if (chLastChar == SLASH)
  553.                                 {
  554.                                 if (!boolInCComment)
  555.                                     {
  556.                                     boolInCPlusComment = true;        // set C++-style comment flag
  557.                                     }  // if !boolInCComment
  558.                                 }  // if chLastChar
  559.                             else
  560.                                 {
  561.                                 if (chLastChar == STAR)
  562.                                     {
  563.                                     if (boolInCComment)
  564.                                         {
  565.                                         boolInCComment = false;        // clear C-style comment flag
  566.                                         chLastChar = '\0';            // impose safe dummy value to prevent recognizing *// as a close C and open C++ comment
  567.                                         chCurrent = '\0';            // impose safe dummy value to prevent recognizing *// as a close C and open C++ comment
  568.                                         }  // if boolInCComment
  569.                                     else
  570.                                         {
  571.                                         // mismatched comments
  572.                                         boolDone = true;            // signal quit
  573.                                         iError = BAD_COMMENT;        // signal mismatched comment
  574.                                         }  // else if boolInCComment
  575.                                     }  // if chLastChar
  576.                                 }  // else if chLastChar
  577.                             }  // if !boolIn1Quote
  578.                         break;
  579.                         }  // case SLASH
  580.                     case STAR :
  581.                         {
  582.                         if (!boolIn1Quote && !boolIn2Quote && !boolInCPlusComment)
  583.                             {
  584.                             if (chLastChar == SLASH)
  585.                                 {
  586.                                 if (!boolInCComment)
  587.                                     {
  588.                                     boolInCComment = true;            // set C-style comment flag
  589.                                     chLastChar = '\0';                // impose safe dummy value to prevent recognizing /*/ as an open and close comment
  590.                                     chCurrent = '\0';                // impose safe dummy value to prevent recognizing /*/ as an open and close comment
  591.                                     }  // if !boolInCComment
  592.                                 else
  593.                                     {
  594.                                     // nested C-style comments - a no-no
  595.                                     boolDone = true;                // signal quit
  596.                                     iError = BAD_NESTED;            // signal nested comments
  597.                                     }  // else if !boolInCComment
  598.                                 }  // if chLastChar
  599.                             }  // if !boolIn1Quote
  600.                         break;
  601.                         }  // case STAR
  602.                     case EOL :
  603.                         {
  604.                         boolInCPlusComment = false;
  605.                         break;
  606.                         }  // case EOL
  607.                     default :
  608.                         {
  609.                         // do nothing
  610.                         break;
  611.                         }  // default
  612.                     }  // switch iChar
  613.                 }  // else if iChar
  614.             }  // else if iChar
  615.         lCurPos++;                                                    // increment the current character position
  616.         chSecondToLastChar = chLastChar;                            // save the second-to-last-read character
  617.         chLastChar = chCurrent;                                        // save the last-read character
  618.         if (boolSelect && (lCurPos >= lEndPos))
  619.             {
  620.             boolDone = true;                                        // all characters have been read
  621.             }  // if boolSelect
  622.         }  // if lCurPos
  623.     else
  624.         {
  625.         boolDone = true;                                            // all characters have been read
  626.         }  // else if lCurPos
  627.     }  // while !boolDone
  628. if ((iError == NO_ERROR) && (lMatch > 0))
  629.     {
  630.     iError = BAD_LEFT;                                                // signal mismatched left pair
  631.     }  // if iError
  632. switch (iError)
  633.     {
  634.     case BAD_LEFT :
  635.         {
  636.         pcallBBEdit->SetSelection(lSavePos,(lSavePos + 1L),-1L);    // select and center the mismatched character
  637.         ReportMismatch(pcallBBEdit,"\pMismatched left brace found!");
  638.         break;
  639.         }  // case BAD_LEFT
  640.     case BAD_RIGHT :
  641.         {
  642.         pcallBBEdit->SetSelection((lCurPos - 1L),lCurPos,-1L);        // select and center the mismatched character
  643.         ReportMismatch(pcallBBEdit,"\pMismatched right brace found!");
  644.         break;
  645.         }  // case BAD_RIGHT
  646.     case BAD_NESTED :
  647.         {
  648.         pcallBBEdit->SetSelection((lCurPos - 2L),lCurPos,-1L);        // select and center the mismatched characters
  649.         ReportMismatch(pcallBBEdit,"\pNested C-style “/* */” comment found!");
  650.         break;
  651.         }  // case BAD_NESTED
  652.     case BAD_COMMENT :
  653.         {
  654.         pcallBBEdit->SetSelection((lCurPos - 2L),lCurPos,-1L);        // select and center the mismatched characters
  655.         ReportMismatch(pcallBBEdit,"\pMismatched C-style “/* */” comment found!");
  656.         break;
  657.         }  // case BAD_COMMENT
  658.     default :
  659.         {
  660.         // no mismatched pairs
  661.         ReportNoMismatch(pcallBBEdit,"\pNo mismatched pairs found!");
  662.         break;
  663.         }  // default
  664.     }  // switch iError
  665. return (iError != NO_ERROR);                                        // signal if a mismatch was found
  666. }  // CheckBraces()
  667.  
  668. Boolean CheckQuotes(ExternalCallbackBlock *pcallBBEdit,int iMode,Handle hText,long lStartPos,long lEndPos)
  669. // find lines having an odd number of single or double quotes
  670.  
  671. {
  672. Boolean boolDone,boolInQuote,boolInCComment,boolInCPlusComment,boolSelect;
  673. char chCurrent,chLastChar,chMatch,chQuote,chSecondToLastChar;
  674. int iError;
  675. long lCurPos,lEOFPos,lMatch,lSavePos;
  676.  
  677. switch (iMode)
  678.     {
  679.     case MODE_DBL_QUOTE :
  680.         {
  681.         chMatch = DBL_QUOTE;
  682.         chQuote = SNGL_QUOTE;
  683.         break;
  684.         }  // case MODE_DBL_QUOTE
  685.     case MODE_SNGL_QUOTE :
  686.         {
  687.         chMatch = SNGL_QUOTE;
  688.         chQuote = DBL_QUOTE;
  689.         break;
  690.         }  // case MODE_SNGL_QUOTE
  691.     default :
  692.         {
  693.         // do nothing
  694.         break;
  695.         }  // default
  696.     }  // switch iMode
  697. lEOFPos = GetHandleSize(hText);
  698. boolSelect = (lEndPos > lStartPos);
  699. boolDone = false;
  700. boolInQuote = false;
  701. boolInCComment = false;
  702. boolInCPlusComment = false;
  703. chLastChar = '\0';
  704. chSecondToLastChar = '\0';
  705. lCurPos = lStartPos;
  706. lSavePos = lStartPos;
  707. lMatch = 0L;
  708. iError = NO_ERROR;
  709.  
  710. while(!boolDone)
  711.     {
  712.     chCurrent = (char) *((*hText) + lCurPos);                        // read a single character
  713.     if (lCurPos < lEOFPos)
  714.         {
  715.         if (chCurrent == chMatch)
  716.             {
  717.             if (!boolInQuote && !boolInCComment && !boolInCPlusComment)
  718.                 {
  719.                 if (!((lMatch & 1L) && (chLastChar == BACK_SLASH) && (chSecondToLastChar != BACK_SLASH)))
  720.                     {
  721.                     // this is not an escaped quote
  722.                     lMatch++;                                        // increment the pair count
  723.                     }  // if !lMatch
  724.                 }  // if !boolInQuote
  725.             }  // if chCurrent
  726.         else
  727.             {
  728.             if (chCurrent == chQuote)
  729.                 {
  730.                 if (!boolInCComment && !boolInCPlusComment && !(lMatch & 1L))
  731.                     {
  732.                     if (!(boolInQuote && (chLastChar == BACK_SLASH) && (chSecondToLastChar != BACK_SLASH)))
  733.                         {
  734.                         // this is not an escaped quote
  735.                         boolInQuote = !boolInQuote;                    // toggle the "in quote" status
  736.                         }  // if !boolInQuote
  737.                     }  // if !boolIncComment
  738.                 }  // if chCurrent
  739.             else
  740.                 {
  741.                 switch (chCurrent)
  742.                     {
  743.                     case SLASH :
  744.                         {
  745.                         if (!boolInQuote && !(lMatch & 1L) && !boolInCPlusComment)
  746.                             {
  747.                             if (chLastChar == SLASH)
  748.                                 {
  749.                                 if (!boolInCComment)
  750.                                     {
  751.                                     boolInCPlusComment = true;        // set C++-style comment flag
  752.                                     }  // if !boolInCComment
  753.                                 }  // if chLastChar
  754.                             else
  755.                                 {
  756.                                 if (chLastChar == STAR)
  757.                                     {
  758.                                     if (boolInCComment)
  759.                                         {
  760.                                         boolInCComment = false;        // clear C-style comment flag
  761.                                         chLastChar = '\0';            // impose safe dummy value to prevent recognizing *// as a close C and open C++ comment
  762.                                         chCurrent = '\0';            // impose safe dummy value to prevent recognizing *// as a close C and open C++ comment
  763.                                         }  // if boolInCComment
  764.                                     else
  765.                                         {
  766.                                         // mismatched comments
  767.                                         boolDone = true;            // signal quit
  768.                                         iError = BAD_COMMENT;        // signal mismatched comment
  769.                                         }  // else if boolInCComment
  770.                                     }  // if chLastChar
  771.                                 }  // else if chLastChar
  772.                             }  // if !boolInQuote
  773.                         break;
  774.                         }  // case SLASH
  775.                     case STAR :
  776.                         {
  777.                         if (!boolInQuote && !(lMatch & 1L) && !boolInCPlusComment)
  778.                             {
  779.                             if (chLastChar == SLASH)
  780.                                 {
  781.                                 if (!boolInCComment)
  782.                                     {
  783.                                     boolInCComment = true;            // set C-style comment flag
  784.                                     chLastChar = '\0';                // impose safe dummy value to prevent recognizing /*/ as an open and close comment
  785.                                     chCurrent = '\0';                // impose safe dummy value to prevent recognizing /*/ as an open and close comment
  786.                                     }  // if !boolInCComment
  787.                                 else
  788.                                     {
  789.                                     // nested C-style comments - a no-no
  790.                                     boolDone = true;                // signal quit
  791.                                     iError = BAD_NESTED;            // signal nested comments
  792.                                     }  // else if !boolInCComment
  793.                                 }  // if chLastChar
  794.                             }  // if !boolInQuote
  795.                         break;
  796.                         }  // case STAR
  797.                     case EOL :
  798.                         {
  799.                         boolInCPlusComment = false;
  800.                         if (lMatch & 1L)
  801.                             {
  802.                             boolDone = true;
  803.                             iError = BAD_QUOTE;                        // signal odd number of quotes
  804.                             }  // if lMatch
  805.                         else
  806.                             {
  807.                             lSavePos = lCurPos + 1;                    // save the new start of line position
  808.                             }  // else if lMatch
  809.                         boolInQuote = false;
  810.                         break;
  811.                         }  // case EOL
  812.                     default :
  813.                         {
  814.                         // do nothing
  815.                         break;
  816.                         }  // default
  817.                     }  // switch chCurrent
  818.                 }  // else if chCurrent
  819.             }  // else if chCurrent
  820.         lCurPos++;                                                    // increment the current character position
  821.         chSecondToLastChar = chLastChar;                            // save the second-to-last-read character
  822.         chLastChar = chCurrent;                                        // save the last-read character
  823.         if (boolSelect && (lCurPos >= lEndPos))
  824.             {
  825.             boolDone = true;                                        // all characters have been read
  826.             }  // if boolSelect
  827.         }  // if lCurPos
  828.     else
  829.         {
  830.         boolDone = true;                                            // all characters have been read
  831.         }  // else if lCurPos
  832.     }  // while !boolDone
  833. if ((iError == NO_ERROR) && (lMatch & 1L))
  834.     {
  835.     iError = BAD_QUOTE;                                                // signal odd number of quotes
  836.     }  // if iError
  837. switch (iError)
  838.     {
  839.     case BAD_QUOTE :
  840.         {
  841.         pcallBBEdit->SetSelection(lSavePos,lCurPos,-1L);            // select and center the mismatched characters
  842.         ReportMismatch(pcallBBEdit,"\pOdd number of quote characters found in a line!");
  843.         break;
  844.         }  // case BAD_RIGHT
  845.     case BAD_NESTED :
  846.         {
  847.         pcallBBEdit->SetSelection((lCurPos - 2L),lCurPos,-1L);        // select and center the mismatched characters
  848.         ReportMismatch(pcallBBEdit,"\pNested C-style “/* */” comment found!");
  849.         break;
  850.         }  // case BAD_NESTED
  851.     case BAD_COMMENT :
  852.         {
  853.         pcallBBEdit->SetSelection((lCurPos - 2L),lCurPos,-1L);        // select and center the mismatched characters
  854.         ReportMismatch(pcallBBEdit,"\pMismatched C-style “/* */” comment found!");
  855.         break;
  856.         }  // case BAD_COMMENT
  857.     default :
  858.         {
  859.         // no mismatched pairs
  860.         ReportNoMismatch(pcallBBEdit,"\pNo lines containing an odd number of quotes found!");
  861.         break;
  862.         }  // default
  863.     }  // switch iError
  864. return (iError != NO_ERROR);                                        // signal if a mismatch was found
  865. }  // CheckQuotes()
  866.  
  867. Boolean CheckComments(ExternalCallbackBlock *pcallBBEdit,Handle hText,long lStartPos,long lEndPos)
  868. // find mismatched C-style comments
  869.  
  870. {
  871. Boolean boolDone,boolIn1Quote,boolIn2Quote,boolInCComment,boolInCPlusComment,boolSelect;
  872. char chCurrent,chLastChar,chSecondToLastChar;
  873. int iError;
  874. long lCurPos,lEOFPos,lMatch,lSavePos;
  875.  
  876. lEOFPos = GetHandleSize(hText);
  877. boolSelect = (lEndPos > lStartPos);
  878. boolDone = false;
  879. boolIn1Quote = false;
  880. boolIn2Quote = false;
  881. boolInCComment = false;
  882. boolInCPlusComment = false;
  883. chLastChar = '\0';
  884. chSecondToLastChar = '\0';
  885. lCurPos = lStartPos;
  886. lSavePos = lStartPos;
  887. lMatch = 0L;
  888. iError = NO_ERROR;
  889.  
  890. while(!boolDone)
  891.     {
  892.     chCurrent = (char) *((*hText) + lCurPos);                                // read a single character
  893.     if (lCurPos < lEOFPos)
  894.         {
  895.         switch (chCurrent)
  896.             {
  897.             case SNGL_QUOTE :
  898.                 {
  899.                 if (!boolIn2Quote && !boolInCComment && !boolInCPlusComment)
  900.                     {
  901.                     if (!(boolIn1Quote && (chLastChar == BACK_SLASH) && (chSecondToLastChar != BACK_SLASH)))
  902.                         {
  903.                         // this is not an escaped quote
  904.                         boolIn1Quote = !boolIn1Quote;                        // toggle the "in single quote" status
  905.                         }  // if !boolInQuote1
  906.                     }  // if !boolIn2Quote
  907.                     break;
  908.                 }  // case SNGL_QUOTE
  909.             case DBL_QUOTE :
  910.                 {
  911.                 if (!boolIn1Quote && !boolInCComment && !boolInCPlusComment)
  912.                     {
  913.                     if (!(boolIn2Quote && (chLastChar == BACK_SLASH) && (chSecondToLastChar != BACK_SLASH)))
  914.                         {
  915.                         // this is not an escaped quote
  916.                         boolIn2Quote = !boolIn2Quote;                        // toggle the "in single quote" status
  917.                         }  // if !boolIn2Quote
  918.                     }  // if !boolIn1Quote
  919.                 break;
  920.                 }  // case DBL_QUOTE
  921.             case SLASH :
  922.                 {
  923.                 if (!boolIn1Quote && !boolIn2Quote && !boolInCPlusComment)
  924.                     {
  925.                     if (chLastChar == SLASH)
  926.                         {
  927.                         if (!boolInCComment)
  928.                             {
  929.                             boolInCPlusComment = true;                        // set C++-style comment flag
  930.                             }  // if !boolInCComment
  931.                         }  // if chLastChar
  932.                     else
  933.                         {
  934.                         if (chLastChar == STAR)
  935.                             {
  936.                             if (boolInCComment)
  937.                                 {
  938.                                 boolInCComment = false;                        // clear C-style comment flag
  939.                                 chLastChar = '\0';                            // impose safe dummy value to prevent recognizing *// as a close C and open C++ comment
  940.                                 chCurrent = '\0';                            // impose safe dummy value to prevent recognizing *// as a close C and open C++ comment
  941.                                 }  // if boolInCComment
  942.                             else
  943.                                 {
  944.                                 // mismatched comments
  945.                                 boolDone = true;                            // signal quit
  946.                                 iError = BAD_RIGHT;                            // signal mismatched comment
  947.                                 }  // else if boolInCComment
  948.                             }  // if chLastChar
  949.                         }  // else if chLastChar
  950.                     }  // if !boolIn1Quote
  951.                 break;
  952.                 }  // case SLASH
  953.             case STAR :
  954.                 {
  955.                 if (!boolIn1Quote && !boolIn2Quote && !boolInCPlusComment)
  956.                     {
  957.                     if (chLastChar == SLASH)
  958.                         {
  959.                         if (!boolInCComment)
  960.                             {
  961.                             boolInCComment = true;                            // set C-style comment flag
  962.                             chLastChar = '\0';                                // impose safe dummy value to prevent recognizing /*/ as an open and close comment
  963.                             chCurrent = '\0';                                // impose safe dummy value to prevent recognizing /*/ as an open and close comment
  964.                             lSavePos = lCurPos;                                // save the current character number
  965.                             }  // if !boolInCComment
  966.                         else
  967.                             {
  968.                             // nested C-style comments - a no-no
  969.                             boolDone = true;                                // signal quit
  970.                             iError = BAD_NESTED;                            // signal nested comments
  971.                             }  // else if !boolInCComment
  972.                         }  // if chLastChar
  973.                     }  // if !boolIn1Quote
  974.                 break;
  975.                 }  // case STAR
  976.             case EOL :
  977.                 {
  978.                 boolInCPlusComment = false;
  979.                 break;
  980.                 }  // case EOL
  981.             default :
  982.                 {
  983.                 // do nothing
  984.                 break;
  985.                 }  // default
  986.             }  // switch chCurrent
  987.         lCurPos++;                                                            // increment the current character position
  988.         chSecondToLastChar = chLastChar;                                    // save the second-to-last-read character
  989.         chLastChar = chCurrent;                                                // save the last-read character
  990.         if (boolSelect && (lCurPos >= lEndPos))
  991.             {
  992.             boolDone = true;                                                // all characters have been read
  993.             }  // if boolSelect
  994.         }  // if lCursPos
  995.     else
  996.         {
  997.         boolDone = true;                                                    // all characters have been read
  998.         }  // else if lCurPos
  999.     }  // while !boolDone
  1000. if ((iError == NO_ERROR) && boolInCComment)
  1001.     {
  1002.     iError = BAD_LEFT;                                                        // signal mis-matched left pair
  1003.     }  // if iError
  1004. switch (iError)
  1005.     {
  1006.     case BAD_LEFT :
  1007.         {
  1008.         pcallBBEdit->SetSelection((lSavePos - 1L),(lSavePos + 1L),-1L);        // select and center the mismatched characters
  1009.         ReportMismatch(pcallBBEdit,"\pMismatched left comment found!");
  1010.         break;
  1011.         }  // case BAD_LEFT
  1012.     case BAD_RIGHT :
  1013.         {
  1014.         pcallBBEdit->SetSelection((lCurPos - 2L),lCurPos,-1L);                // select and center the mismatched characters
  1015.         ReportMismatch(pcallBBEdit,"\pMismatched right comment found!");
  1016.         break;
  1017.         }  // case BAD_RIGHT
  1018.     case BAD_NESTED :
  1019.         {
  1020.         pcallBBEdit->SetSelection((lCurPos - 2L),lCurPos,-1L);                // select and center the mismatched characters
  1021.         ReportMismatch(pcallBBEdit,"\pNested C-style “/* */” comment found!");
  1022.         break;
  1023.         }  // case BAD_NESTED
  1024.     default :
  1025.         {
  1026.         // no mismatched comments
  1027.         ReportNoMismatch(pcallBBEdit,"\pNo mismatched comments found!");
  1028.         break;
  1029.         }  // default
  1030.     }  // switch iError
  1031. return (iError != NO_ERROR);                                                // signal if a mismatch was found
  1032. }  // CheckComments()
  1033.  
  1034. pascal void main(ExternalCallbackBlock *pcallBBEdit,WindowPtr pwndFront)
  1035. {
  1036. Boolean boolDone,boolMismatch;
  1037. int iMode;
  1038. long lEndPos,lFirstChar,lStartPos;
  1039. #if !USESROUTINEDESCRIPTORS
  1040. long lOldA4;
  1041. #endif // !USESROUTINEDESCRIPTORS
  1042. Handle hText;
  1043. OSErr oseTest;
  1044. SysEnvRec serWorld;
  1045.  
  1046. #if !USESROUTINEDESCRIPTORS
  1047. lOldA4 = SetCurrentA4();                                                        // setup A4 to point to global data segment
  1048. #endif // !USESROUTINEDESCRIPTORS
  1049. gumfBBEdit = NewModalFilterProc(pcallBBEdit->StandardFilter);                    // get a routine descriptor (or UniversalProcPtr for 68k) for the BBEdit standard dialog filter function
  1050. if (pcallBBEdit->version > 1)
  1051.     {
  1052.     oseTest = SysEnvirons(2,&serWorld);                                            // the the system environment
  1053.     if ((oseTest == noErr) && (serWorld.systemVersion >= (short) 0x0700))
  1054.         {
  1055.         // System 7.0 or later is available
  1056.         pcallBBEdit->GetSelection(&lStartPos,&lEndPos,&lFirstChar);                // get the current selection (if any)
  1057.         hText = pcallBBEdit->GetWindowContents(pwndFront);
  1058.         if (hText != nil)
  1059.             {
  1060.             boolDone = PairsDialog(pcallBBEdit,&iMode);
  1061.             if (!boolDone)
  1062.                 {
  1063.                 // OK was pressed - do the indicated pairs checking
  1064.                 boolMismatch = false;                                            // initialize
  1065.                 pcallBBEdit->SetSelection(lStartPos,lStartPos,lFirstChar);        // remove the original selection (if any) to work-around highlight updating bug
  1066.                 switch (iMode)
  1067.                     {
  1068.                     case MODE_CURLY_BRACE :
  1069.                     case MODE_SQUARE_BRACE :
  1070.                     case MODE_PARENTHESIS :
  1071.                         {
  1072.                         boolMismatch = CheckBraces(pcallBBEdit,iMode,hText,lStartPos,lEndPos);
  1073.                         break;
  1074.                         }  // case MODE_CURLY_BRACE … MODE_PARENTHESIS
  1075.                     case MODE_DBL_QUOTE :
  1076.                     case MODE_SNGL_QUOTE :
  1077.                         {
  1078.                         boolMismatch = CheckQuotes(pcallBBEdit,iMode,hText,lStartPos,lEndPos);
  1079.                         break;
  1080.                         }  // case MODE_DBL_QUOTE,MODE_SNGL_QUOTE
  1081.                     case MODE_COMMENT :
  1082.                         {
  1083.                         boolMismatch = CheckComments(pcallBBEdit,hText,lStartPos,lEndPos);
  1084.                         break;
  1085.                         }  // case MODE_COMMENT
  1086.                     default :
  1087.                         {
  1088.                         // do nothing
  1089.                         break;
  1090.                         }  // default
  1091.                     }  // switch iMode
  1092.                 if (!boolMismatch)
  1093.                     {
  1094.                     // need to restore the original selection
  1095.                     pcallBBEdit->SetSelection(lStartPos,lEndPos,lFirstChar);    // restore the original selection (if any)
  1096.                     }  // if !boolMismatch
  1097.                 }  // if !boolDone
  1098.             }  // if hText
  1099.         else
  1100.             {
  1101.             ReportError(pcallBBEdit,"\pCouldn't get a handle to the window text.","\p");
  1102.             }  // else if hText
  1103.         } // if oseTest
  1104.     else
  1105.         {
  1106.         ReportError(pcallBBEdit,"\pSystem 7.0 or later is required.","\p");
  1107.         }  // else if oseTest
  1108.     }  // if pcallBBEdit->version
  1109. else
  1110.     {
  1111.     ReportError(pcallBBEdit,"\pVersion 2.2 or later of BBEdit is required.","\p");
  1112.     }  // else if pcallBBEdit->version
  1113. DisposeRoutineDescriptor((UniversalProcPtr) gumfBBEdit);                        // dispose of the routine descriptor
  1114. #if !USESROUTINEDESCRIPTORS
  1115. SetA4(lOldA4);                                                                    //    restore A4 to saved value before returning
  1116. #endif // !USESROUTINEDESCRIPTORS
  1117. }  // main()
  1118.  
  1119. // end of Pairs.c